#ifndef BEZIER_CURVE_H
#define BEZIER_CURVE_H

#include <vector>
#include <cmath>
#include <iostream>
#include "Function.hpp"
#include "matplotlibcpp.h"
using namespace std;
namespace plt = matplotlibcpp;
const double Pi = acos(-1.);

// 计算贝塞尔曲线的控制点
vector<dot> calculateBezierControlPoints(const Function& f, const double& t1, const double& t2, int n) {
    dot p1 = f(t1);
    dot p2 = f(t2);
    dot q0,q1,q2,q3;
    q0 = p1;
    q1.x = p1.x + f.derivative(t1).x * (1.0/3) *(1.0/n);
    q1.y = p1.y + f.derivative(t1).y * (1.0/3) *(1.0/n);
    q2.x = p2.x - f.derivative(t2).x * (1.0/3) *(1.0/n);
    q2.y = p2.y - f.derivative(t2).y * (1.0/3) *(1.0/n);
    q3 = p2;
    return {q0, q1, q2, q3};
}

// 计算三次贝塞尔曲线上的点
dot evaluateBezier(const vector<dot>& controlPoints, double t) {
    double u = 1 - t;
    double tt = t * t;
    double uu = u * u;
    double uuu = uu * u;
    double ttt = tt * t;
    double uut = uu * t;
    double utt = u * tt;

    dot point;
    point.x = (uuu * controlPoints[0].x) + (3 * uut * controlPoints[1].x) + (3 * utt * controlPoints[2].x) + (ttt * controlPoints[3].x);
    point.y = (uuu * controlPoints[0].y) + (3 * uut * controlPoints[1].y) + (3 * utt * controlPoints[2].y) + (ttt * controlPoints[3].y);
    return point;
}

void approximateWithBezierCurves( const Function&f, int m, double t_min, double t_max) {
    double segment_length = static_cast<double>(t_max - t_min) / m; // 每段的长度
    double t1 = t_min;
    double t2 = t1+segment_length;
    vector<double> x_values, y_values;
    for (int i = 0; i < m; ++i) {
            vector<dot> controlPoints = calculateBezierControlPoints(f, t1, t2, m);

            // 绘制贝塞尔曲线
            // vector<double> x_values, y_values;
            int n = 100;
            for (double j = t1; j < t2; j += segment_length / n) {
                dot point = evaluateBezier(controlPoints, j);
                x_values.push_back(point.x);
                y_values.push_back(point.y);
            }
            //plt::plot(x_values, y_values, "*-");
            t1 = t2;
            t2 += segment_length;    
    }
    plt::named_plot("Bezier_Curve", x_values, y_values, "y-");
    plt::xlabel("X");
    plt::ylabel("Y");
    plt::grid(true);
    // plt::show();
}
#endif // BEZIER_CURVE_H